package com.cts.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cts.entity.LoginLog;
import com.cts.entity.User;
import com.cts.mapper.UserMapper;
import com.cts.model.dto.LoginUser;
import com.cts.model.vo.PageResultVO;
import com.cts.model.vo.Result;
import com.cts.service.LoginLogService;
import com.cts.service.UserService;
import com.cts.util.IpUtils;
import com.cts.util.JwtUtils;
import com.cts.util.RedisUtils;
import eu.bitwalker.useragentutils.UserAgent;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Objects;

/**
* @author tongshengchen
* @description 针对表【user】的数据库操作Service实现
* @createDate 2023-02-06 12:25:57
*/
@Slf4j
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User>
    implements UserService {

    @Autowired
    private AuthenticationConfiguration authenticationConfiguration;

    @Autowired
    UserMapper userMapper;

    @Autowired
    RedisUtils redisUtils;

    @Autowired
    LoginLogService loginLogService;


    @Override
    public Result login(User user) throws Exception {
        UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(user.getUsername(), user.getPassword());
        AuthenticationManager authenticationManager = authenticationConfiguration.getAuthenticationManager();

        Authentication authenticate = authenticationManager.authenticate(usernamePasswordAuthenticationToken);
        // 判断authenticate 是否为空，如果为空则认证没有通过
        if (Objects.isNull(authenticate)) {
            throw new RuntimeException("登陆认证失败");
        }

        // 使用Jwt根据UserId生成Token
        LoginUser loginUser = (LoginUser)authenticate.getPrincipal();
        String username = loginUser.getUsername().toString();
        String jwt = JwtUtils.generateToken(username);
        HashMap<String, String> token = new HashMap<>();
        token.put("token", jwt);

        // 写入redis
        redisUtils.set("Login:"+username, loginUser);

        // 写入登陆成功日志
        LoginLog loginLog = handleLog(loginUser.getUsername(), "登陆", true);
        loginLogService.save(loginLog);
        log.info("登陆完成");
        return Result.ok("登陆成功",token);
    }

    @Override
    public Result getUserByUsername(HttpServletRequest httpServletRequest) {
        LoginUser loginUser = (LoginUser) httpServletRequest.getAttribute("LoginUser");
        User user =  loginUser.getUser();
        if (Objects.isNull(user) || StringUtils.isEmpty(user.getUsername()) || StringUtils.isBlank(user.getUsername())) {
            QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
            userQueryWrapper.eq("username", user.getUsername());
            user = userMapper.selectOne(userQueryWrapper);
            if (StringUtils.isEmpty(user.getUsername()) || StringUtils.isBlank(user.getUsername()) ) {
                return Result.error("请求失败");
            }
        }
        return Result.ok("请求成功", user);
    }

    @Override
    public Result logout(HttpServletRequest httpServletRequest) {
        LoginUser loginUser = (LoginUser) httpServletRequest.getAttribute("LoginUser");
        redisUtils.remove("BlogListDTO:login:" + loginUser.getUsername());
        // 写出登出日志
        LoginLog loginLog = handleLog(loginUser.getUsername(), "登出", true);
        loginLogService.save(loginLog);
        log.info("登出完成");
        return Result.ok("请求成功");
    }


    private LoginLog handleLog(String username, String description, Boolean status) {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        String ip = IpUtils.getIpAddress(request);
        String ipSource = IpUtils.getCityInfo(ip);
        String userAgentHeader = request.getHeader("User-Agent");
        UserAgent userAgent = UserAgent.parseUserAgentString(userAgentHeader);
        String os = userAgent.getOperatingSystem().getName();
        String browser = userAgent.getBrowser().toString();

        LoginLog loginLog = new LoginLog(username, ip, ipSource, status, description, userAgentHeader, os, browser);
        loginLog.setCreateTime(LocalDateTime.now());
        return loginLog;
    }
}




